<script setup lang="ts">
  import SubMenu from './sub.vue';
  import Item from './item.vue';
  import type { MenuInjection, MenuProps } from './types';
  import { rootMenuInjectionKey } from './types';

  defineOptions({
    name: 'MainMenu',
  });

  const props = withDefaults(defineProps<MenuProps>(), {
    accordion: true,
    defaultOpeneds: () => [],
    mode: 'vertical',
    collapse: false,
    showCollapseName: false,
  });

  const activeIndex = ref<MenuInjection['activeIndex']>(props.value);
  const items = ref<MenuInjection['items']>({});
  const subMenus = ref<MenuInjection['subMenus']>({});
  const openedMenus = ref<MenuInjection['openedMenus']>(props.defaultOpeneds.slice(0));
  const mouseInMenu = ref<MenuInjection['mouseInMenu']>([]);
  const isMenuPopup = computed<MenuInjection['isMenuPopup']>(() => {
    return props.mode === 'horizontal' || (props.mode === 'vertical' && props.collapse);
  });

  // 解析传入的 menu 数据，并保存到 items 和 subMenus 对象中
  function initItems(menu: MenuProps['menu'], parentPaths: string[] = []) {
    menu.forEach((item) => {
      const index = item.path ?? JSON.stringify(item);
      if (item.children) {
        const indexPath = [...parentPaths, index];
        subMenus.value[index] = {
          index,
          indexPath,
          active: false,
        };
        initItems(item.children, indexPath);
      } else {
        items.value[index] = {
          index,
          indexPath: parentPaths,
        };
      }
    });
  }

  const openMenu: MenuInjection['openMenu'] = (index, indexPath) => {
    if (openedMenus.value.includes(index)) {
      return;
    }
    if (props.accordion) {
      openedMenus.value = openedMenus.value.filter((key) => indexPath.includes(key));
    }
    openedMenus.value.push(index);
  };
  const closeMenu: MenuInjection['closeMenu'] = (index) => {
    if (Array.isArray(index)) {
      nextTick(() => {
        closeMenu(index.at(-1)!);
        if (index.length > 1) {
          closeMenu(index.slice(0, -1));
        }
      });
      return;
    }
    Object.keys(subMenus.value).forEach((item) => {
      if (subMenus.value[item].indexPath.includes(index)) {
        openedMenus.value = openedMenus.value.filter((item) => item !== index);
      }
    });
  };

  function setSubMenusActive(index: string) {
    for (const key in subMenus.value) {
      subMenus.value[key].active = false;
    }
    subMenus.value[index]?.indexPath.forEach((idx) => {
      subMenus.value[idx].active = true;
    });
    items.value[index]?.indexPath.forEach((idx) => {
      subMenus.value[idx].active = true;
    });
  }

  const handleMenuItemClick: MenuInjection['handleMenuItemClick'] = (index) => {
    if (props.mode === 'horizontal' || props.collapse) {
      openedMenus.value = [];
    }
    setSubMenusActive(index);
  };
  const handleSubMenuClick: MenuInjection['handleSubMenuClick'] = (index, indexPath) => {
    if (openedMenus.value.includes(index)) {
      closeMenu(index);
    } else {
      openMenu(index, indexPath);
    }
  };

  function initMenu() {
    const activeItem = activeIndex.value && items.value[activeIndex.value];
    setSubMenusActive(activeIndex.value);
    if (!activeItem || props.collapse) {
      return;
    }
    // 展开该菜单项的路径上所有子菜单
    activeItem.indexPath.forEach((index) => {
      const subMenu = subMenus.value[index];
      subMenu && openMenu(index, subMenu.indexPath);
    });
  }

  watch(
    () => props.menu,
    (val) => {
      initItems(val);
      initMenu();
    },
    {
      deep: true,
      immediate: true,
    },
  );

  watch(
    () => props.value,
    (currentValue) => {
      if (!items.value[currentValue]) {
        activeIndex.value = '';
      }
      const item =
        items.value[currentValue] ||
        (activeIndex.value && items.value[activeIndex.value]) ||
        items.value[props.value];
      if (item) {
        activeIndex.value = item.index;
      } else {
        activeIndex.value = currentValue;
      }
      initMenu();
    },
  );

  watch(
    () => props.collapse,
    (value) => {
      if (value) {
        openedMenus.value = [];
      }
      initMenu();
    },
  );

  provide(
    rootMenuInjectionKey,
    reactive({
      props,
      items,
      subMenus,
      activeIndex,
      openedMenus,
      mouseInMenu,
      isMenuPopup,
      openMenu,
      closeMenu,
      handleMenuItemClick,
      handleSubMenuClick,
    }),
  );
</script>

<template>
  <div
    class="flex flex-col of-hidden transition-all"
    :class="{
      'w-[200px]': !isMenuPopup && props.mode === 'vertical',
      'w-[64px]': isMenuPopup && props.mode === 'vertical',
      'h-[80px]': props.mode === 'horizontal',
      'flex-row! w-auto': isMenuPopup && props.mode === 'horizontal',
    }"
  >
    <template v-for="item in menu" :key="item.path ?? JSON.stringify(item)">
      <template v-if="item.meta?.menu !== false">
        <SubMenu
          v-if="item.children?.length"
          :menu="item"
          :unique-key="[item.path ?? JSON.stringify(item)]"
        />
        <Item
          v-else
          :item="item"
          :unique-key="[item.path ?? JSON.stringify(item)]"
          @click="handleMenuItemClick(item.path ?? JSON.stringify(item))"
        />
      </template>
    </template>
  </div>
</template>
